spring security oauth2 client |
您所在的位置:网站首页 › cannot resolve configuration property jwttoken header › spring security oauth2 client |
在我们开发系统时,返回给前端的信息均具有统一的格式,但在使用spring security oauth2时,遇到client_id或client_secret错误时,返回信息为如下格式: { "timestamp": "2020-08-03T20:41:54.776+0800", "status": 401, "error": "Unauthorized", "message": "Unauthorized", "path": "/uaa/oauth/token" }上述格式并不符合我们的开发规范,因此需要对spring security oauth2返回的信息进行处理。 通过debug发现,当通过设置header信息"Authorization Basic xeeEOnBpZzE="并提交认证时,oauth2使用的是Basic方式的认证,使用的过滤器为BasicAuthenticationFilter,最终使用BasicAuthenticationEntryPoint来生成返回信息。 经过各种尝试后,终于发现解决oauth2返回统一信息的方法。 解决方案如下: 在configure(AuthorizationServerSecurityConfigurer oauthServerSecurity) {}中新增如下代码: oauthServerSecurity.addTokenEndpointAuthenticationFilter( new BasicAuthenticationFilter(authenticationManager, customAuthenticationEntryPoint));这样便可以覆盖默认的Basic authentication过滤器,并实现自定义的错误响应信息。 完整代码如下: @Override public void configure(AuthorizationServerSecurityConfigurer oauthServerSecurity) { oauthServerSecurity.tokenKeyAccess("permitAll()") .checkTokenAccess("isAuthenticated()") .allowFormAuthenticationForClients(); oauthServerSecurity.addTokenEndpointAuthenticationFilter( new BasicAuthenticationFilter(authenticationManager, customAuthenticationEntryPoint)); }自定义CustomAuthenticationEntryPoint @Component("customAuthenticationEntryPoint") public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint { private final ObjectMapper objectMapper = new ObjectMapper(); @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException { response.setStatus(HttpStatus.OK.value()); R r = R.error(HttpStatus.UNAUTHORIZED.value(), "client_id或client_secret错误"); response.setHeader("Content-Type", "application/json;charset=utf-8"); response.getWriter().print(JSON.toJSONString(r)); response.getWriter().flush(); } }但此处有坑: 因password模式需要注入authenticationManagerBean @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception{ return super.authenticationManagerBean(); }因此,在上述代码中如果直接使用全局注入的authenticationManager会导致其在进行client_id和client_secret校验时,使用的是UserDetailsService而不是ClientDetailsService进行验证,导致最终验证失败。 因此,需要使用自定义的authenticationManager对上边有坑的代码进行改造,改造结果如下: oauthServerSecurity.addTokenEndpointAuthenticationFilter( new BasicAuthenticationFilter(authenticationManager(), customAuthenticationEntryPoint));哪么,如果自定义authenticationManager呢? 首先,我们需要定义一下ClientDetailsService @Bean public AuthenticationProvider daoAuthenticationProvider() { DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider(); daoAuthenticationProvider.setUserDetailsService(new ClientDetailsUserDetailsService(customClientDetailsService())); daoAuthenticationProvider.setHideUserNotFoundExceptions(false); return daoAuthenticationProvider; }其次,定义一个AuthenticationProvider @Bean ClientDetailsService customClientDetailsService() { OauthClientDetailsService clientDetailsService = new OauthClientDetailsService(dataSource); clientDetailsService.setSelectClientDetailsSql(SecurityConstants.DEFAULT_SELECT_STATEMENT); clientDetailsService.setFindClientDetailsSql(SecurityConstants.DEFAULT_FIND_STATEMENT); return clientDetailsService; }最终,定义我们的自定义authenticationManager。 @Bean public AuthenticationManager authenticationManager() { return authentication -> daoAuthenticationProvider().authenticate(authentication); }至次,便完成了Oauth2认证服务器Unauthorized异常信息的自定义。 效果如下: 改造前: 改造后: |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |